using System;
using System.ServiceModel;
using System.Diagnostics;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.EnterpriseLibrary.Logging.ExtraInformation;
using Microsoft.Practices.EnterpriseLibrary.Logging.Filters;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Metro.Admin.DataAccess;
using System.Collections.Generic; 

namespace Metro.CurrenciesService
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class Notification : INotification
    {
        INotificationContract callback = null;

        public delegate void OrderChangeEventHandler(object sender, OrderChangeEventArgs e);
        public static event OrderChangeEventHandler OrderChangeEvent;
        
        OrderChangeEventHandler orderChangeEventHandler = null;
 
        public delegate void TransactionsChangeEventHandler(object sender, TransactionsChangeEventArgs e);
        public static event TransactionsChangeEventHandler TransactionsChangeEvent;

        TransactionsChangeEventHandler transactionsChangeEventHandler = null;

        public delegate void ParametersChangeEventHandler(object sender, ParametersChangeEventArgs e);
        public static event ParametersChangeEventHandler ParametersChangeEvent;

        ParametersChangeEventHandler parametersChangeEventHandler = null;

        public delegate void StatsChangeEventHandler(object sender, StatsChangeEventArgs e);
        public static event StatsChangeEventHandler StatsChangeEvent;

        StatsChangeEventHandler statsChangeEventHandler = null;



        public void Subscribe()
        {
            try
            {
                callback = OperationContext.Current.GetCallbackChannel<INotificationContract>();
                
                orderChangeEventHandler = new OrderChangeEventHandler(OrderChangeHandler);
                OrderChangeEvent += orderChangeEventHandler;
                
                transactionsChangeEventHandler = new TransactionsChangeEventHandler(TransactionsChangeHandler);
                TransactionsChangeEvent += transactionsChangeEventHandler;

                parametersChangeEventHandler = new ParametersChangeEventHandler(ParametersChangeHandler);
                ParametersChangeEvent += parametersChangeEventHandler;

                statsChangeEventHandler = new StatsChangeEventHandler(StatsChangeHandler);
                StatsChangeEvent += statsChangeEventHandler;

            }
            catch (Exception ex)
            {
                LogEntry log = new LogEntry();
                log.EventId = 100;
                log.Message = ex.Message;
                log.Categories.Add("Subscribe");
                log.Severity = TraceEventType.Error;
                log.Priority = 0;
                log.ProcessName = "Subscribe Method";
                Logger.Write(log);
            }
        }

        public void Unsubscribe()
        {
            try
            {
                OrderChangeEvent -= orderChangeEventHandler;
                TransactionsChangeEvent -= transactionsChangeEventHandler;
                ParametersChangeEvent -= parametersChangeEventHandler;
                StatsChangeEvent -= statsChangeEventHandler;
            }
            catch (Exception ex)
            {
                LogEntry log = new LogEntry();
                log.EventId = 100;
                log.Message = ex.Message;
                log.Categories.Add("Unsubscribe");
                log.Severity = TraceEventType.Error;
                log.Priority = 0;
                log.ProcessName = "Unsubscribe Method";
                Logger.Write(log);
            }
        }

        public void PublishOrderChange(Metro.Admin.BusinessEntities.OrderOperation operation, Metro.Admin.BusinessEntities.Order order)
        {
            Order orderDA = new Order();  
            try
            {
                switch(operation)
                {
                    case Metro.Admin.BusinessEntities.OrderOperation.New:
                        orderDA.AddOrder(order,true); 
                        break;

                    case Metro.Admin.BusinessEntities.OrderOperation.Update:
                        orderDA.UpdateOrder(order); 
                        break;

                    case Metro.Admin.BusinessEntities.OrderOperation.Delete:
                        orderDA.DeleteOrder(order);  
                        break;
                }

                OrderChangeEventArgs e = new OrderChangeEventArgs();
                e.operation  = operation;
                e.order = order;
                OrderChangeEvent(this, e);

            }
            catch (Exception ex)
            {
                LogEntry log = new LogEntry();
                log.EventId = 100;
                log.Message = ex.Message;
                log.Categories.Add("PublishOrderChange");
                log.Severity = TraceEventType.Error;
                log.Priority = 0;
                log.ProcessName = "PublishOrderChange Method";
                Logger.Write(log);
            }
        }
        
        public void PublishTransactionsChange(Metro.Admin.BusinessEntities.TransaccionOperation operation, List<Metro.Admin.BusinessEntities.Transaction> transactions)
        {
            Transaction transactionDA = new Transaction();
            Order orderDA = new Order();
            Metro.Admin.BusinessEntities.Stats stats = null;

            try
            {
                switch (operation)
                {
                    case Metro.Admin.BusinessEntities.TransaccionOperation.New:
                        foreach (Metro.Admin.BusinessEntities.Transaction transaction in transactions)
                        {
                            if (!orderDA.ExistsOrder(transaction.OriginalOrder))
                            {
                                orderDA.AddOrder(transaction.OriginalOrder,false);  
                            }
                            transactionDA.AddTransaction(transaction);
                        }
                        break;

                    case Metro.Admin.BusinessEntities.TransaccionOperation.Delete:
                        foreach (Metro.Admin.BusinessEntities.Transaction transaction in transactions)
                        {
                            transactionDA.DeleteTransaction(transaction);
                        }
                        break;
                }

                TransactionsChangeEventArgs e = new TransactionsChangeEventArgs();
                e.operation = operation;
                e.transactions = transactions;
                TransactionsChangeEvent(this, e);

                stats = transactionDA.GetStats(DateTime.Today);

                StatsChangeEventArgs arg = new StatsChangeEventArgs();
                arg.stats = stats;
                StatsChangeEvent(this, arg);
            }
            catch (Exception ex)
            {
                LogEntry log = new LogEntry();
                log.EventId = 100;
                log.Message = ex.Message;
                log.Categories.Add("PublishTransactionsChange");
                log.Severity = TraceEventType.Error;
                log.Priority = 0;
                log.ProcessName = "PublishTransactionsChange Method";
                Logger.Write(log);
            }
        }

        public void PublishParameterChange(List<Metro.Admin.BusinessEntities.Parameter> parameterList)
        {

            try
            {
                ParametersChangeEventArgs e = new ParametersChangeEventArgs();
                e.parameterList = parameterList;
                ParametersChangeEvent(this, e);
            }
            catch (Exception ex)
            {
                LogEntry log = new LogEntry();
                log.EventId = 100;
                log.Message = ex.Message;
                log.Categories.Add("PublishParameterChange");
                log.Severity = TraceEventType.Error;
                log.Priority = 0;
                log.ProcessName = "PublishParameterChange Method";
                Logger.Write(log);
            }
        }

        public void OrderChangeHandler(object sender, OrderChangeEventArgs e)
        {
           callback.OrderChange(e.operation,e.order);
        }

        public void TransactionsChangeHandler(object sender, TransactionsChangeEventArgs e)
        {
            callback.TransactionsChange(e.operation, e.transactions);
        }

        public void ParametersChangeHandler(object sender, ParametersChangeEventArgs e)
        {
            callback.ParameterChange(e.parameterList);
        }

        public void StatsChangeHandler(object sender,StatsChangeEventArgs e)
        {
            callback.StatsChange(e.stats); 
        }

    }
}